﻿using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using static 摸鱼._数据库;
using static 摸鱼.全局类;

namespace 摸鱼
{
    public static class 编译
    {
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static string 求值(this string 中缀表达式)
        {
            if (中缀表达式 == null)
                return "0";
            string[] 数组 = 中缀表达式.Split(',');
            for (int i = 0; i < 数组.Length; i++)
                数组[i] = 逆后缀求值(中缀转后缀(数组[i]));

            return string.Join(',', 数组);
        }

        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe string 中缀转后缀(string 中缀表达式)
        {
            //格式化表达式
            中缀表达式 = 中缀表达式.Replace('\n', ' ')
                                   .Replace('\r', ' ')
                                   .Replace("==", ";")
                                   .Replace("&&", "&")
                                   .Replace("||", "|")
                                   .Replace('[', '{')
                                   .Replace(']', '}')
                                   .Replace(">=", "]")
                                   .Replace("<=", "[")
                                   .Replace('=', '#')
                                   .Replace(';', '=')
                                   .Replace(" ", "");

            StringBuilder postfix表达式 = new(Convert.ToInt32(中缀表达式.Length * 1.8));
            Stack<char> 符号 = new();
            bool 连续符 = true;
            foreach (char c in 中缀表达式)
            {
                if (符号优先级.ContainsKey(c) && 连续符 == false) //是存在的运算符
                {
                    while (符号.Count > 0 && 符号.Peek() != '(' && 符号优先级[c] <= 符号优先级[符号.Peek()])
                    {
                        postfix表达式.Append(' ');
                        postfix表达式.Append(符号.Pop());
                    }
                    符号.Push(c);
                    连续符 = true;
                }
                else if (c == '(')
                {
                    符号.Push(c);
                    连续符 = true;
                }
                else if (c == ')')
                {
                    while (符号.Count > 0 && 符号.Peek() != '(')
                    {
                        postfix表达式.Append(' ');
                        postfix表达式.Append(符号.Pop());
                    }

                    if (符号.Count > 0 && 符号.Peek() == '(')
                        符号.Pop(); // 弹出相应的 '(' 
                    连续符 = false;
                }
                else //是其他
                {
                    if (连续符 == false)
                        postfix表达式.Append(c);
                    else
                    {
                        postfix表达式.Append(' ');
                        postfix表达式.Append(c);
                    }
                    连续符 = false;
                }
            }
            while (符号.Count > 0)
            {
                postfix表达式.Append(' ');
                postfix表达式.Append(符号.Pop());
            }
            /*if (postfix表达式 == null || postfix表达式.Length == 0)
                Debugger.Break();*/
            if (postfix表达式[0] == ' ')
            { postfix表达式.Remove(0, 1); }
            return postfix表达式.ToString();
        }

        //数字越大, 优先级越高
        public static System.Collections.Generic.Dictionary<char, int> 符号优先级 = new()
        {   { '|', -2 },
            { '&', -1 },
            //#赋值
            { '#', 0 },
            { '?', 1 }, { ':', 1 }, 
            //=相等
            { '=', 1 }, 
            //[小于或等于
            { '[', 1 },
            //]大于或等于
            { ']', 1 },
            { '<', 1 }, { '>', 1 },
            { '+', 2 }, { '-', 2 },
            { '*', 3 }, { '/', 3 },
            { '^', 4 },
            { '.', 5 } };
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe string 逆后缀求值(string 后序表达式)
        {
            Stack<string> 文本堆栈 = new();
            string[] 数组 = 后序表达式.Split(' ');
            foreach (string 值 in 数组)
            {
                char 字符 = 值[0];
                if (符号优先级.ContainsKey(字符) && 值.Length == 1)
                {
                    string b = 文本堆栈.Pop();
                    string a = 文本堆栈.Pop();
                    string 计算结果;

                    //对于变量名，直接进行赋值和函数计算
                    switch (字符)
                    {
                        case '#':
                            赋值计算(a, b, out 计算结果);
                            break;
                        case '.':
                            if (int.TryParse(a, out _))
                                计算结果 = a + '.' + b;
                            else
                                计算结果 = 扩展函数(a, b);
                            break;
                        default:
                            计算结果 = 字符.计算(a, b);
                            break;
                    }
                    文本堆栈.Push(计算结果);
                }
                else //是数值或变量
                    文本堆栈.Push(值);
            }
            string 结果 = 文本堆栈.Pop();

            var result = 结果.提取索引();
            if (result.索引 != -1)
            {
                if (result.变量名.取值(result.索引, out var 值))
                    结果 = 值;
            }
            else if (数据库.变量.TryGetValue(结果, out _变量 变量))
            {
                结果 = 变量.值;
            }

            return 结果;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe string 计算(this char 运算符, string a, string b)
        {
            int aLength = a.格式化(out string[] a组);
            int bLength = b.格式化(out string[] b组);
            if (aLength == bLength)
            {
                for (int i = 0; i < aLength; i++)
                    a组[i] = 运算符.计算2(a组[i], b组[i]);
                return string.Join(',', a组);
            }
            else if (aLength == 1)
            {
                for (int i = 0; i < bLength; i++)
                    b组[i] = 运算符.计算2(a组[0], b组[i]);
                return string.Join(',', b组);
            }
            else if (bLength == 1)
            {
                for (int i = 0; i < aLength; i++)
                    a组[i] = 运算符.计算2(a组[i], b组[0]);
                return string.Join(',', a组);
            }
            else
            {
                MoyuControl.MsgboxThrow(true, "计算公式错误，可能是数组不对称");
                return null;
            }
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe int 格式化(this string x, out string[] outItems)
        {
            var result = x.提取索引();
            //是数组索引元素
            if (result.索引 != -1 && result.变量名.取值(result.索引, out var 值))
            {
                outItems = [值];
                return 1;
            }
            //是变量或数组
            else if (数据库.变量.TryGetValue(x, out _变量 变量))
            {
                outItems = 变量.值.Split(',');
                return outItems.Length;
            }
            //是值
            outItems = x.Split(',');
            return outItems.Length;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe double V(string x)
        {
            if (数据库.变量.TryGetValue(x, out _变量 变量))
                if (double.TryParse(变量.值, out double Number))
                    return Number;
            if (double.TryParse(x, out double result))
                return result;
            else
            {
                MoyuControl.MsgboxThrow(true, "表达式计算错误, 非数字也非变量：" + x);
                return 0.0;
            }
        }
        /// <summary>
        /// 这一步理论上左值绝对不是变量名
        /// </summary>
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static unsafe string 计算2(this char 字符, string a, string b)
        {
            double 计算结果;
            switch (字符)
            {
                case '+':
                    计算结果 = V(a) + V(b);
                    break;
                case '-':
                    计算结果 = V(a) - V(b);
                    break;
                case '*':
                    计算结果 = V(a) * V(b);
                    break;
                case '/':
                    计算结果 = V(a) / V(b);
                    break;
                case '^':
                    计算结果 = Math.Pow(V(a), V(b));
                    break;
                case '>':
                    计算结果 = V(a) > V(b) ? 1 : 0;
                    break;
                case '<':
                    计算结果 = V(a) < V(b) ? 1 : 0;
                    break;
                case '=':
                    计算结果 = V(a) == V(b) ? 1 : 0;
                    break;
                case ']':
                    计算结果 = V(a) >= V(b) ? 1 : 0;
                    break;
                case '[':
                    计算结果 = V(a) <= V(b) ? 1 : 0;
                    break;
                case '?':
                    计算结果 = V(a) == 1 ? V(b) : V(a);
                    break;
                case ':':
                    计算结果 = V(a) == 0 ? V(b) : V(a);
                    break;
                case '#':
                    赋值计算(a, b, out 计算结果);
                    break;
                case '&':
                    计算结果 = V(a) == 1 && V(b) == 1 ? 1 : 0;
                    break;
                case '|':
                    计算结果 = V(a) == 1 || V(b) == 1 ? 1 : 0;
                    break;
                case '.':
                    if (int.TryParse(a, out _))
                        计算结果 = double.Parse(a + '.' + b);
                    else
                        计算结果 = double.Parse(扩展函数(a, b));
                    break;
                default:
                    MoyuControl.MsgboxThrow(true, "表达式计算错误，错误符号：" + 字符);
                    计算结果 = 0;
                    break;
            }
            return 计算结果.ToString();
        }

        private static string 扩展函数(string a, string b)
        {
            switch (b)
            {
                case "Count" or "Length" or "count" or "length" or "长度":
                    return 数组长度();
                default:
                    MoyuControl.MsgboxThrow(true, "扩展函数错误：" + b);
                    return "0";
            }

            string 数组长度()
            {
                string 数组数据 = a.取值();
                string[] 数组 = 数组数据.Split(',');
                string 长度;
                if (数组.Length == 1 && 数组[0] == "")
                    长度 = "0";
                else
                    长度 = 数组.Length.ToString();
                return 长度;
            }
        }
        private static void 赋值计算(string a, string b, out double dest)
        {
            _赋值计算(ref b);

            var resulta = a.提取索引();
            if (resulta.索引 != -1)
            {
                resulta.变量名.赋值(resulta.索引, b);
                dest = V(resulta.变量名);
            }
            else
            {
                a.赋值(b);
                dest = V(a);
            }
        }
        private static void 赋值计算(string a, string b, out string dest)
        {
            _赋值计算(ref b);

            var resulta = a.提取索引();
            if (resulta.索引 != -1)
            {
                resulta.变量名.赋值(resulta.索引, b);
                dest = resulta.变量名;
            }
            else
            {
                a.赋值(b);
                dest = a;
            }
        }
        private static void _赋值计算(ref string b)
        {
            var resultb = b.提取索引();
            if (resultb.索引 != -1)
            {
                if (resultb.变量名.取值(resultb.索引, out var b索引值))
                    b = b索引值;
            }
            else if (数据库.变量.TryGetValue(b, out _变量 变量))
                b = 变量.值;
        }

        //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//



        public static void 类型转换(string 变量名, string 新类型)
        {
            变量名.取值(out _变量 变量);
            switch (变量.类型)
            {
                case "数值":
                    switch (新类型)
                    {
                        case "数值": return;
                        case "文本": 变量._类型转换(变量名, 新类型, 变量.值); break;
                        case "图片": 变量._类型转换(变量名, 新类型, ""); break;
                    }
                    break;
                case "文本":
                    switch (新类型)
                    {
                        case "数值":
                            if (double.TryParse(变量.值, out double 新值))
                            { 变量._类型转换(变量名, 新类型, 新值.ToString()); }
                            else { 变量._类型转换(变量名, 新类型, "0"); }
                            break;
                        case "文本": return;
                        case "图片": 变量._类型转换(变量名, 新类型, 变量.值); break;
                    }
                    break;
                case "图片":
                    switch (新类型)
                    {
                        case "数值": 变量._类型转换(变量名, 新类型, "0"); break;
                        case "文本": 变量._类型转换(变量名, 新类型, 变量.值); break;
                        case "图片": return;
                    }
                    break;
            }
        }
        private static void _类型转换(this _变量 变量, string 变量名, string 新类型, string 值)
        {
            变量名.删除变量(变量名.Get级别());
            switch (true)
            {
                case var t when t == (变量.全局 != null):
                    值.创建变量(变量.全局, 变量名, 新类型);
                    break;
                case var t when t == (变量.方案 != null):
                    值.创建变量(变量.方案, 变量名, 新类型);
                    break;
                case var t when t == (变量.步骤 != null):
                    值.创建变量(变量.步骤, 变量名, 新类型);
                    break;
            }
        }
        public static bool 删除变量(this string 变量名, object 对象)
        {
            if (!数据库.变量.TryGetValue(变量名, out _变量? 变量))
                return false;
            switch (对象)
            {
                case null:
                case _数据库:
                    数据库.子变量.Remove(变量名);
                    break;
                case _方案 x:
                    x.子变量.Remove(变量名);
                    break;
                case _方案._步骤 x:
                    x.子变量.Remove(变量名);
                    break;
            }
            数据库.变量.TryRemove(变量名);
            return true;
        }
        public static object Get级别(this string 变量名)
        {
            if (!数据库.变量.TryGetValue(变量名, out _变量? 变量))
                return null;
            switch (true)
            {
                case var k when 变量.步骤 != null:
                    return 数据库.当前步骤;
                case var k when 变量.方案 != null:
                    return 数据库.当前方案;
                case var k when 变量.全局 != null:
                    return 数据库;
                default:
                    return null;
            }
        }

        public static string 改名(this string old名, string new名)
        {
            if (数据库.变量.ContainsKey(new名))
                return old名;
            if (!old名.取值(out _变量? 变量)) return old名;
            object 目标级别 = null;
            switch (true)
            {
                case var t when t == (变量.步骤 != null):
                    数据库.当前步骤.子变量[数据库.当前步骤.子变量.IndexOf(old名)] = new名;
                    目标级别 = 数据库.当前步骤;
                    break;
                case var t when t == (变量.方案 != null):
                    数据库.当前方案.子变量[数据库.当前方案.子变量.IndexOf(old名)] = new名;
                    目标级别 = 数据库.当前方案;
                    break;
                case var t when t == (变量.全局 != null):
                    数据库.子变量[数据库.子变量.IndexOf(old名)] = new名;
                    目标级别 = 数据库;
                    break;
            }
            数据库.变量.TryRemove(old名);

            数据库.变量.Add(new名, new(变量, 目标级别));
            return new名;
        }
        public class 多类型<T, K, M> where K : class, M, T
        {
            private T t;
            private K k;
            private M m;
            public 多类型(T value) => t = value;
            public 多类型(K value) => k = value;
            public 多类型(M value) => m = value;
            //Get
            public static implicit operator T(多类型<T, K, M> 实例) => 实例.t;
            public static implicit operator K(多类型<T, K, M> 实例) => 实例.k;
            public static implicit operator M(多类型<T, K, M> 实例) => 实例.m;
            //Set
            public static implicit operator 多类型<T, K, M>(T 值) => new(值);
            public static implicit operator 多类型<T, K, M>(K 值) => new(值);
            public static implicit operator 多类型<T, K, M>(M 值) => new(值);
        }
        public static void 覆盖图片(this string 变量名, List<MoyuBitmap> bitmap)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].图片 = bitmap;
        }
        public static void 添加图片(this string 变量名, MoyuBitmap bitmap)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].图片.Add(bitmap);
        }
        public static void 覆盖图片(this string 变量名, List<Bitmap> bitmap)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].图片 = bitmap.Select(x => new MoyuBitmap(x)).ToList();
        }
        public static void 覆盖图片(this string 变量名, Bitmap bitmap)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].图片 = new List<MoyuBitmap> { new MoyuBitmap(bitmap) };
        }
        public static void 添加图片(this string 变量名, Bitmap bitmap)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].图片.Add(new MoyuBitmap(bitmap));
        }
        public static void 赋值(this string 变量名, string 值)
        {
            if (!数据库.变量.ContainsKey(变量名))
                return;
            数据库.变量[变量名].值 = 值;
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static void 赋值(this string 变量名, int 索引号, string 值)
        {
            string[] 数组;
            if (数据库.变量.TryGetValue(变量名, out _变量 变量))
            {
                数组 = 变量.值.Split(',');
                if (数组.Length < 索引号)
                    return;
                数组[索引号] = 值;
                string 新值 = string.Join(",", 数组);
                变量.值 = 新值;
                数据库.变量[变量名] = 变量;
            }
        }
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static bool 取值(this string 变量名, int 索引号, out string? 值)
        {
            值 = string.Empty;
            string[] 数组;
            if (数据库.变量.TryGetValue(变量名, out _变量 变量))
            {
                数组 = 变量.值.Split(',');
                if (数组.Length < 索引号)
                    return false;
                值 = 数组[索引号];
                return true;
            }
            return false;
        }

        private static string 数组匹配 = @"(.*?)\{(.*?)\}";
        [SkipLocalsInit]
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        public static (string 变量名, int 索引) 提取索引(this string 字符串)
        {
            string 变量名 = string.Empty;
            int 索引 = -1;
            Match match = Regex.Match(字符串, 数组匹配);
            if (match.Success)
            {
                变量名 = match.Groups[1].Value;
                string 索引s = match.Groups[2].Value;
                if (int.TryParse(索引s, out int x))
                    索引 = x;
                else if (int.TryParse(索引s.求值(), out x))
                    索引 = x;
                else
                {
                    MoyuControl.MsgboxThrow(true, "数组索引必须是数值或变量数值!");
                }
            }
            return (变量名, 索引);
        }
        public static bool 取值(this string 变量名, out string? 值)
        {
            return 数据库.变量.TryGetValue(变量名, out _变量 变量) ? (值 = 变量.值) != "" : (值 = "") == "";
        }
        public static bool 取值(this string 变量名, out _变量? 变量)
        {
            return 数据库.变量.TryGetValue(变量名, out 变量);
        }
        public static string 取值(this string 变量名)
        {
            if (数据库.变量 != null && 数据库.变量.Count > 0)
                if (数据库.变量.TryGetValue(变量名, out _变量 变量))
                    return 变量.值;
            return "";
        }
        public static List<MoyuBitmap> 取图(this string 变量名)
        {
            MoyuControl.MsgboxThrow(!数据库.变量.ContainsKey(变量名), "没有图片, 请检查图片变量是否正确");
            return 数据库.变量[变量名].图片;
        }
        public static void 创建变量(this string 值, string 名字, string 类型 = "数值")
        {
            if (名字 == "变量" || 名字 == "图片") { 名字 = 名字 + (数据库.变量闲ID.Dequeue()); }
            if (数据库.当前步骤 != null)
            {
                数据库.当前步骤.子变量.Add(名字);
                值._创建变量(new() { 步骤 = 数据库.当前步骤 }, 名字, 类型);
                return;
            }
            if (数据库.当前方案 != null)
            {
                数据库.当前方案.子变量.Add(名字);
                值._创建变量(new() { 方案 = 数据库.当前方案 }, 名字, 类型);
                return;
            }
            数据库.子变量.Add(名字);
            值._创建变量(new() { 全局 = new() }, 名字, 类型);
        }
        public static void 创建变量(this List<MoyuBitmap> 图片, string 名字, string 类型 = "图片")
        {
            if (名字 == "变量" || 名字 == "图片")
                名字 = 名字 + (数据库.变量闲ID.Dequeue());
            if (数据库.当前步骤 != null)
            {
                数据库.当前步骤.子变量.Add(名字);
                图片._创建变量(new() { 步骤 = 数据库.当前步骤 }, 名字, 类型);
                return;
            }
            if (数据库.当前方案 != null)
            {
                数据库.当前方案.子变量.Add(名字);
                图片._创建变量(new() { 方案 = 数据库.当前方案 }, 名字, 类型);
                return;
            }
            数据库.子变量.Add(名字);
            图片._创建变量(new() { 全局 = new() }, 名字, 类型);
        }
        public static void 创建变量(this string 值, _数据库 目标, string 名字 = "变量", string 类型 = "数值")
        {
            if (目标 == null) { return; }
            if (名字 == "变量" || 名字 == "图片") { 名字 = 名字 + (数据库.变量闲ID.Dequeue()); }
            值._创建变量(new() { 全局 = 目标 }, 名字, 类型); 目标.子变量.Add(名字);
        }
        public static void 创建变量(this string 值, _数据库._方案 目标, string 名字 = "变量", string 类型 = "数值")
        {
            if (目标 == null) { return; }
            if (名字 == "变量" || 名字 == "图片") { 名字 = 名字 + (数据库.变量闲ID.Dequeue()); }
            值._创建变量(new() { 方案 = 目标 }, 名字, 类型); 目标.子变量.Add(名字);
        }
        public static void 创建变量(this string 值, _数据库._方案._步骤 目标, string 名字 = "变量", string 类型 = "数值")
        {
            if (目标 == null) { return; }
            if (名字 == "变量" || 名字 == "图片") { 名字 = 名字 + (数据库.变量闲ID.Dequeue()); }
            值._创建变量(new() { 步骤 = 目标 }, 名字, 类型); 目标.子变量.Add(名字);
        }
        private static void _创建变量(this string 值, _变量 变量, string 名字, string 类型)
        {
            变量.类型 = 类型;
            变量.值 = 值;
            数据库.变量.TryAdd(名字, 变量);
        }
        private static void _创建变量(this List<MoyuBitmap> bitmap, _变量 变量, string 名字, string 类型)
        {
            变量.类型 = 类型;
            变量.图片 = bitmap.Select(x => new MoyuBitmap(x)).ToList();
            数据库.变量.TryAdd(名字, 变量);
        }



    }
}

